/**    
 * 文件名：MySiftVisualWordsSearch.java    
 *    
 * 版本信息：    
 * 日期：2014年3月31日    
 * xyj 足下 xyj 2014     
 * 版权所有    
 *    
 */
package learn.visual.words;

import static com.googlecode.javacv.cpp.opencv_highgui.cvLoadImage;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.io.FileUtils;

import com.googlecode.javacv.cpp.opencv_core.CvMat;
import com.googlecode.javacv.cpp.opencv_core.IplImage;
import com.googlecode.javacv.cpp.opencv_features2d.DescriptorExtractor;
import com.googlecode.javacv.cpp.opencv_features2d.KeyPoint;
import com.googlecode.javacv.cpp.opencv_nonfree.SIFT;

/**
 * @项目名称：opencv-test
 * @类名称：MySiftVisualWordsSearch
 * @类描述：
 * @创建人：zhuyi
 * @创建时间：2014年3月31日 上午11:26:29
 * @修改人：zhuyi
 * @修改时间：2014年3月31日 上午11:26:29
 * @修改备注：
 * @version
 * 
 */
public class MySiftVisualWordsSearch {

    private static int k = 500;

    private static int dims = 128;

    private static int emax = 300;

    private static String visualWordsPath = "visualWords1";

    private static String histogramPath = "histogram300";

    public static void main(String[] args) throws Exception {

        // 图片读取sift
        IplImage image = cvLoadImage("e:/ii/40988.jpg");
        KeyPoint keyPoints = new KeyPoint();
        int nFeatures = 400;
        int nOctaveLayers = 3;
        float contrastThreshold = 0.03f;
        int edgeThreshold = 10;
        float sigma = 1.6f;
        SIFT sift = new SIFT(nFeatures, nOctaveLayers, contrastThreshold, edgeThreshold, sigma);
        DescriptorExtractor siftDesc = DescriptorExtractor.create("SIFT");
        sift.detect(image, null, keyPoints);
        CvMat desc = new CvMat(null);
        siftDesc.compute(image, keyPoints, desc);

        // 读取视觉词典
        double[][] vss = new double[k][dims];
        List<String> vlines = FileUtils.readLines(new File(visualWordsPath));
        for (int i = 0; i < vlines.size(); i++) {
            String vline = vlines.get(i);
            String[] _vlines = vline.split("\t");
            for (int j = 0; j < _vlines.length; j++) {
                vss[i][j] = Double.parseDouble(_vlines[j]);
            }
        }

        // 计算直方图
        int[] h = new int[vss.length];
        for (int i = 0; i < vss.length; i++) {
            h[i] = 0;
        }

        for (int i = 0; i < desc.rows(); i++) {
            double[] ps = new double[dims];
            for (int j = 0; j < dims; j++) {
                double p = desc.get(i, j);
                ps[j] = p;
            }

            // System.out.println("ps");
            // printDoubleArray(ps);

            // 遍历虚拟词
            for (int v = 0; v < vss.length; v++) {
                double[] vs = vss[v];
                // System.out.println("vs");
                // printDoubleArray(vs);
                double d = euclid(ps, vs);
                if (d < emax) {
                    h[v] += 1;
                }
            }

        }

        // 读取图片直方图
        Map<String, int[]> hs = new HashMap<String, int[]>();
        List<String> hLines = FileUtils.readLines(new File(histogramPath));
        for (int i = 0; i < hLines.size(); i++) {
            String hLine = hLines.get(i);
            String[] _hLines = hLine.split("\t");
            String file = _hLines[0];
            int[] fh = new int[k];
            for (int j = 1; j < _hLines.length; j++) {
                fh[j - 1] = Integer.parseInt(_hLines[j]);
            }
            hs.put(file, fh);
        }

        // 计算最近的图片
        Map<String, Double> result = new HashMap<String, Double>();
        for (String key : hs.keySet()) {
            int[] _hs = hs.get(key);
            double d = euclid(_hs, h);
            // System.out.println(key + "\t" + d);
            result.put(key, d);
        }

        mapSortDouble(result);

    }

    public static double euclid(double[] d1, double[] d2) {
        assert d1.length == d2.length;

        double d = 0.0d;
        for (int i = 0; i < d1.length; i++) {
            double x = d1[i];
            double y = d2[i];
            d += Math.pow((x - y), 2);
        }

        return Math.sqrt(d);
    }

    public static double euclid(int[] d1, int[] d2) {
        assert d1.length == d2.length;

        double d = 0.0d;
        for (int i = 0; i < d1.length; i++) {
            double x = d1[i];
            double y = d2[i];
            d += Math.pow((x - y), 2);
        }

        return Math.sqrt(d);
    }

    public static void mapSortDouble(Map<String, Double> map) {
        List<Map.Entry<String, Double>> listData = new ArrayList<Map.Entry<String, Double>>(map.entrySet());
        System.out.println("排序前listData：");
        System.out.println(listData);
        // 排序
        Collections.sort(listData, new Comparator<Map.Entry<String, Double>>() {
            @Override
            public int compare(Map.Entry<String, Double> o1, Map.Entry<String, Double> o2) {
                return o2.getValue() - o1.getValue() > 0 ? -1 : 1;
            }
        });
        System.out.println("排序后listData：");
        for (int i = 0; i < 10; i++) {
            Map.Entry<String, Double> data = listData.get(i);
            System.out.println(data.getKey() + "\t" + data.getValue());

        }
    }
}
